package com.genersoft.iot.vmp.vmanager.biz;

import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.business.BizHttpService;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.task.DetectMessageList;
import com.genersoft.iot.vmp.utils.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

@CrossOrigin
@RestController
@RequestMapping("/api")
public class BizController {

    private final static Logger logger = LoggerFactory.getLogger(BizController.class);

    @Value("${business.uploadDir}")
    String uploadDir;
    @Value("${media.ip}")
    String mediaIp;
    @Value("${media.wanIp}")
    String mediaWanIp;

    @Autowired
    private IVideoManagerStorager storager;

    @Autowired
    private BizHttpService bizHttpService;

    @Autowired
    private ZLMRESTfulUtils zlmresTfulUtils;

    private Map<String, ArrayDeque<String>> snapData = new HashMap<>();

    private Map<String, String> inspectionState = new HashMap<>();

    @ResponseBody
    @PostMapping(value = "/biz/ops")
    public JSONObject ops(@RequestBody JSONObject json) {
        int requestId = json.getInteger("request_id");
        String cameraId = json.getString("camera_id");
        String deviceId = json.getString("device_id");
        String command = json.getString("command");
        int hAngle = json.getIntValue("h_angle");
        int vAngle = json.getIntValue("v_angle");
        String pointTag = json.getString("point_tag");

        logger.info("biz ops body:" + json.toString());

        JSONObject result = new JSONObject();
        result.put("response_id", requestId);
        result.put("camera_id", cameraId);
        result.put("h_angle", hAngle);
        result.put("v_angle", vAngle);

        if (cameraId == null) {
            result.put("res", -1);
            result.put("msg", "params error");
            return result;
        }

        // 查找设备
        Device currentDevice = storager.queryVideoDevice(cameraId);
        if (currentDevice == null) {
            result.put("res", -2);
            result.put("msg", "device not found");
            return result;
        }

        DeviceChannel deviceChannel = null;
        List<DeviceChannel> channels = storager.queryChannelsByDeviceId(currentDevice.getDeviceId());
        if (channels.size() > 0) {
            deviceChannel = channels.get(0);
        }

        if (deviceChannel == null) {
            result.put("res", -2);
            result.put("msg", "channel not found");
            return result;
        }

        int speed = 90;
        // 左右调整位置
        int lRdirection = 0;
        //float lRPerAnge = 11;//每秒转动角度
        float lRPerAnge = 13f;//每秒转动角度
        int lrCurrentAngle = deviceChannel.getHAngle();
        logger.info("lrCurrentAngle:" + lrCurrentAngle);
        if (hAngle > lrCurrentAngle) {
            lRdirection = 1; // 顺时针
        } if (hAngle < lrCurrentAngle) {
            lRdirection = 2;
        }

        // 开始调整位置
        int uDdirection = 0;
        //float lRPerAnge = 11;//每秒转动角度
        float uDPerAnge = 5f;//每秒转动角度
        int uDCurrentAngle = deviceChannel.getVAngle();
        logger.info("uDCurrentAngle:" + uDCurrentAngle);
        if (vAngle > uDCurrentAngle) {
            uDdirection = 1; // 下
        } if (vAngle < uDCurrentAngle) {
            uDdirection = 2;
        }

        // 都是0，初始校准
        if (hAngle == 0 && vAngle == 0) {
            lRdirection = 2;
            uDdirection = 2;
            int direction = lRdirection + uDdirection * 4;
            boolean ptzResult = ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), direction, speed);
            if (ptzResult) {
                int waitMsc = 30000;
                try {
                    Thread.sleep(waitMsc);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 停止转动
                ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), 0, 0);
            } else {
                hAngle = deviceChannel.getHAngle();
                vAngle = deviceChannel.getVAngle();
            }
        } else {
            // 开始左右转动
            if (lRdirection > 0) {
                boolean ptzResult = ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), lRdirection, speed);
                if (ptzResult) {
                    int dValue = Math.abs(lrCurrentAngle - hAngle);
                    int waitMsc = (int) ((dValue / lRPerAnge) * 1000);
                    if (hAngle == 0) { // 0度校准，多等会
                        if (waitMsc  == 0) {
                            waitMsc = 20000;
                        } else {
                            waitMsc += 3000;
                        }
                    }
                    try {
                        Thread.sleep(waitMsc);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 停止转动
                    ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), 0, 0);
                } else {
                    hAngle = deviceChannel.getHAngle();
                }
            }

            // 开始上下转动
            if (uDdirection > 0) {
                uDdirection = uDdirection * 4;
                boolean ptzResult = ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), uDdirection, speed);
                if (ptzResult) {
                    int dValue = Math.abs(uDCurrentAngle - vAngle);
                    int waitMsc = (int) ((dValue / uDPerAnge) * 1000);
                    if (vAngle == 0) { // 0度校准，多等会
                        if (waitMsc  == 0) {
                            waitMsc = 15000;
                        } else {
                            waitMsc += 3000;
                        }
                    }
                    try {
                        Thread.sleep(waitMsc);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 停止转动
                    ptz(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), 0, 0);
                } else {
                    vAngle = deviceChannel.getVAngle();
                }
            }
        }

        storager.updateChannelAngle(deviceChannel.getDeviceId(), deviceChannel.getChannelId(), hAngle, vAngle);

        // 等待2秒，让云台停稳
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 拉流
        if (command.equals("shot")) {
            String playUrl = "/api/play/" + currentDevice.getDeviceId() + "/" + deviceChannel.getChannelId();
            String response = bizHttpService.executeLocalGetApi(playUrl);
            String streamId = null, streamUrl = null, snapUrl = null;
            if (response != null) {
                JSONObject jsonObject = JSONObject.parseObject(response);
                if (jsonObject.containsKey("streamId") && jsonObject.containsKey("rtmp")) {
                    streamId = jsonObject.getString("streamId");
                    streamUrl = jsonObject.getString("rtmp");
                    if (!mediaWanIp.isEmpty()) {
                        streamUrl = streamUrl.replace(mediaWanIp, mediaIp);
                    }
                    // 判断流是否存在
                    int i = 0;
                    boolean streamExist = false;
                    while (i < 20) {
                        JSONObject mediaJson = zlmresTfulUtils.getMediaList("rtp", "rtmp", streamId);
                        if (mediaJson.containsKey("data") && mediaJson.getJSONArray("data").size() > 0) {
                            streamExist = true;
                            break;
                        }
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ++i;
                    }

                    if (streamExist) {
                        // 截图
                        String dateDir = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
                        String picName = cameraId.replace(".", "-") + "-" + cameraId + "-" + System.currentTimeMillis() + ".jpg";
                        String fileName = dateDir + File.separator + picName;
                        String destFile = uploadDir + fileName;
                        FileUtil.makeDirs(destFile);
                        boolean snapResult = zlmresTfulUtils.getSnap(streamUrl, destFile);
                        if (!snapResult) {
                            logger.info(String.format("ops get snap failure  %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId()));
                            result.put("res", -4);
                            result.put("msg", "snap failure");
                        } else {
                            result.put("res", 0);
                            result.put("msg", "success");

                            JSONObject detectJsonObject = new JSONObject();
                            detectJsonObject.put("file", destFile);
                            detectJsonObject.put("camera_id", cameraId);
                            if (inspectionState.containsKey(cameraId)) {
                                detectJsonObject.put("state", inspectionState.get(cameraId));
                            } else {
                                detectJsonObject.put("state", "stop");
                            }
                            if (pointTag != null) {
                                detectJsonObject.put("point_tag", pointTag);
                            }
                            detectJsonObject.put("method", "ops");

                            try {
                                DetectMessageList.produce(detectJsonObject);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        logger.info(String.format("ops stream not found %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId()));
                        result.put("res", -3);
                        result.put("msg", "pull stream failure stream not found");
                    }

                    // 关闭流
                    // 判断是否还有人观看
                    int totalReaderCount = 0;
                    JSONObject mediaJson = zlmresTfulUtils.getMediaList("rtp", "rtmp", streamId);
                    if (mediaJson.containsKey("data") && mediaJson.getJSONArray("data").size() > 0) {
                        JSONObject mediaObject = mediaJson.getJSONArray("data").getJSONObject(0);
                        totalReaderCount = mediaObject.getIntValue("totalReaderCount");
                    }
                    if (totalReaderCount == 0) {
                        String stopUrl = "/api/play/" + streamId + "/stop";
                        bizHttpService.executeLocalPostApi(stopUrl, null);
                    }
                } else {
                    String msg = jsonObject.getString("msg");
                    logger.info(String.format("ops play url fail streamId null %s %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId(), msg));
                    result.put("res", -3);
                    result.put("msg", "pull stream failure, streamId null");
                }
            } else {
                logger.info(String.format("ops play url fail %s %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId(), "response is null"));
                result.put("res", -3);
                result.put("msg", "pull stream failure");
            }
        }

        return result;
    }

    @ResponseBody
    @PostMapping(value = "/biz/inspection")
    public JSONObject inspection(@RequestBody JSONObject json) {
        int requestId = json.getInteger("request_id");
        String cameraId = json.getString("camera_id");
        String deviceId = json.getString("device_id");
        String state = json.getString("state");

        logger.info("biz inspection body:" + json.toString());

        JSONObject result = new JSONObject();
        result.put("response_id", requestId);
        result.put("camera_id", cameraId);
        result.put("device_id", deviceId);
        result.put("state", state);
        // 查找设备
        Device currentDevice = storager.queryVideoDevice(cameraId);
        if (currentDevice == null) {
            result.put("res", -2);
            result.put("msg", "device not found");
            return result;
        }

        DeviceChannel deviceChannel = null;
        List<DeviceChannel> channels = storager.queryChannelsByDeviceId(currentDevice.getDeviceId());
        if (channels.size() > 0) {
            deviceChannel = channels.get(0);
        }

        if (deviceChannel == null) {
            result.put("res", -2);
            result.put("msg", "channel not found");
            return result;
        }

        inspectionState.put(cameraId, state);

        JSONObject detectJsonObject = new JSONObject();
        detectJsonObject.put("request_id", requestId);
        detectJsonObject.put("camera_id", cameraId);
        detectJsonObject.put("state", state);
        detectJsonObject.put("method", "inspection");

        try {
            DetectMessageList.produce(detectJsonObject);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 开始巡检拉流
//        if (state.equals("start")) {
//            String playUrl = "/api/play/" + currentDevice.getDeviceId() + "/" + deviceChannel.getChannelId();
//            String response = bizHttpService.executeLocalGetApi(playUrl);
//            String streamId = null, streamUrl = null, snapUrl = null;
//            if (response != null) {
//                JSONObject jsonObject = JSONObject.parseObject(response);
//                if (jsonObject.containsKey("streamId") && jsonObject.containsKey("rtmp")) {
//                    streamId = jsonObject.getString("streamId");
//                    streamUrl = jsonObject.getString("rtmp");
//                    if (!mediaWanIp.isEmpty()) {
//                        streamUrl = streamUrl.replace(mediaWanIp, mediaIp);
//                    }
//                    // 判断流是否存在
//                    int i = 0;
//                    boolean streamExist = false;
//                    while (i < 20) {
//                        JSONObject mediaJson = zlmresTfulUtils.getMediaList("rtp", "rtmp", streamId);
//                        if (mediaJson.containsKey("data") && mediaJson.getJSONArray("data").size() > 0) {
//                            streamExist = true;
//                            break;
//                        }
//                        try {
//                            Thread.sleep(1000);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        ++i;
//                    }
//                    if (streamExist) {
//                        logger.info(String.format("inspection play url success streamId null %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId()));
//                        // 录像
//                        JSONObject recordJson = zlmresTfulUtils.startRecord("rtp", streamId, 1);
//                    }
//                } else {
//                    String msg = jsonObject.getString("msg");
//                    logger.info(String.format("inspection play url fail streamId null %s %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId(), msg));
//                    result.put("res", -3);
//                    result.put("msg", "pull stream failure, streamId null");
//                }
//            } else {
//                logger.info(String.format("inspection play url fail %s %s %s", currentDevice.getDeviceId(), deviceChannel.getChannelId(), "response is null"));
//                result.put("res", -3);
//                result.put("msg", "pull stream failure");
//            }
//        } else if (state.equals("stop")) {
//            zlmresTfulUtils.stopRecord()
//        }


        return result;
    }

    @GetMapping(value = "/biz/getsnap/{cameraId}")
    public JSONObject getSnap(@PathVariable String cameraId) {
        JSONObject result = new JSONObject();
        result.put("camera_id", cameraId);
        if (inspectionState.containsKey(cameraId)) {
            result.put("state", inspectionState.get(cameraId));
        } else {
            result.put("state", "stop");
        }

        if (snapData.containsKey(cameraId)) {
            ArrayDeque<String> snaps = snapData.get(cameraId);
            if (snaps.size() > 0) {
                String file = snaps.poll();
                result.put("file", file);
            }
        }

        return result;
    }

    private boolean ptz(String deviceId, String channelId, int direction, int speed) {
        String url = "/api/ptz/" + deviceId + "/"
                + channelId + "?cmdCode=" + direction + "&horizonSpeed=" + speed + "&verticalSpeed=" + speed + "&zoomSpeed=0";
        String result = bizHttpService.executeLocalPostApi(url, null);
        return "success".equals(result);
    }
}
